package cn.edu.cuit.mockfns.fam.transition;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.edu.cuit.mockfns.fam.Action;
import cn.edu.cuit.mockfns.fam.Condition;
import cn.edu.cuit.mockfns.fam.FAMEngine;
import cn.edu.cuit.mockfns.fam.tuples.CommonNullEvent;
import cn.edu.cuit.mockfns.fam.tuples.Event;
import cn.edu.cuit.mockfns.fam.tuples.Function;
import cn.edu.cuit.mockfns.fam.tuples.State;

/**
 * TransitionTable defines all transitions for one business logic. So that,I'd like to define it as
 * a static field in <code>BusinessLogic</code> class
 * */
public class TransitionTable
{
    private Map<State, List<TransitionMatcher>> transitionTable;
    private FAMEngine famEngine;

    public TransitionTable(FAMEngine famEngine)
    {
        this();
        this.famEngine = famEngine;
    }

    public TransitionTable()
    {
        transitionTable = new HashMap<State, List<TransitionMatcher>>();
    }

    public void defineTransition( State fromState, Event<?> event, State toState, Condition transitionCondition,
        Action action )
    {
        if( event == null )
        {
            event = new CommonNullEvent();
        }

        Function function = new Function( famEngine, fromState, event, toState, transitionCondition );
        Transition transition = new Transition( fromState, toState, function, action );
        TransitionMatcher matcher = new TransitionMatcher( fromState, event, transition );

        for( State keyState : transitionTable.keySet() )
        {
            if( fromState == keyState && transitionTable.get( fromState ) != null )
            {
                transitionTable.get( fromState ).add( matcher );
                return;
            }
        }

        ArrayList<TransitionMatcher> matchers = new ArrayList<TransitionMatcher>();
        matchers.add( matcher );

        defineTransition( fromState, matchers );
    }

    public void defineTransition( State fromState, Event<?> event, State toState, Condition transitionCondition )
    {
        defineTransition( fromState, event, toState, transitionCondition, null );
    }

    public void defineTransition( State fromState, Event<?> event, State toState )
    {
        defineTransition( fromState, event, toState, null, null );
    }

    public void defineTransition( int fromState, int eventId, int toStateId, Condition transitionCondition,
        Action action )
    {
    }

    public void defineTransition( int fromState, int eventId, int toStateId, Condition transitionCondition )
    {
        defineTransition( fromState, eventId, toStateId, transitionCondition, null );
    }

    public void defineTransition( int fromStateId, int eventId, int toStateId )
    {
        defineTransition( fromStateId, eventId, toStateId, null, null );
    }

    public Map<State, List<TransitionMatcher>> getTransitionTable()
    {
        return transitionTable;
    }

    public void defineTransition( State fromState, List<TransitionMatcher> matchers )
    {
        transitionTable.put( fromState, matchers );
    }

    public List<TransitionMatcher> getTransitionMatcherForState( State state )
    {
        for( State keyState : transitionTable.keySet() )
        {
            if( state.getClass() == keyState.getClass() )
            {
                return transitionTable.get( keyState );
            }
        }
        return null;
    }
}
